﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ChronoScript_Compiler.CodeGen
{
    public enum VType
    {
        Dword = 1,
        Word = 2,
        String = 3,
        Pointer = 4,
        Byte = 5,
        DArray = 6,
        StringArray = 7,
        Float = 8,
        Object = 9,
        Boolean = 10,
        NotFound = 11,
        Void = 12,
    }
    public class Variable
    {
        public string Name;
        public string RealName;
        public VType Type;
    }
    public class SymbolTable
    {
        public class Scope
        {
            public string Name;
            public List<Variable> variables = new List<Variable>();
        }

        public Stack<Scope> scopes = new Stack<Scope>();
        private static uint tempIndex = 0;

        public string CreateTempString(string val)
        {
            CodeGen.Assembler.CreateString(tempIndex.ToString() + "___stringLiteral", val);
            tempIndex++;
            return (tempIndex - 1).ToString() + "___stringLiteral";
        }
        public void DeclareInt32(string name)
        {
            Variable v = new Variable();
            v.RealName = getScopeName() + name;
            v.Name = name;
            v.Type = VType.Dword;
            scopes.Peek().variables.Add(v);
            CodeGen.Assembler.CreateBuffer(v.RealName, 4);
        }
        public void DeclareBool(string name)
        {
            Variable v = new Variable();
            v.RealName = getScopeName() + name;
            v.Name = name;
            v.Type = VType.Boolean;
            scopes.Peek().variables.Add(v);
            CodeGen.Assembler.CreateBuffer(v.RealName, 4);
        }
        public void DeclareString(string name)
        {
            Variable v = new Variable();
            v.RealName = getScopeName() + name;
            v.Name = name;
            v.Type = VType.String;
            scopes.Peek().variables.Add(v);
            CodeGen.Assembler.CreateBuffer(v.RealName, 4);
        }
        public VType GetType(string T)
        {
            foreach (Scope sc in this.scopes)
            {
                foreach (Variable v in sc.variables)
                {
                    if (v.Name == T)
                        return v.Type;
                }
            }
            return VType.NotFound;
        }
        public bool Exists(string T)
        {
            foreach (Scope sc in this.scopes)
            {
                foreach (Variable v in sc.variables)
                {
                    if (v.Name == T)
                        return true;
                }
            }
            return false;
        }
        public string getScopeName()
        {
            string ret = "_";
            foreach (Scope sc in this.scopes)
            {
                ret += sc.Name + "_";
            }
            return ret + "__";
        }
        public void BeginScope(string name)
        {
            Scope sc = new Scope();
            sc.Name = name;
            scopes.Push(sc);
        }
        public void BeginScope()
        {
            Scope sc = new Scope();
            sc.Name = getScopeName() + "_scope_" + tempIndex.ToString();
            scopes.Push(sc);
            tempIndex++;
        }
        public void EndScope()
        {
            scopes.Pop();
        }
        public SymbolTable()
        {
        }
        public string this[string Var]
        {
            get
            {
                foreach (Scope sc in this.scopes)
                {
                    foreach (Variable v in sc.variables)
                    {
                        if (v.Name == Var)
                            return v.RealName;
                    }
                }
                return "";
            }
        }

        public VType getType(string Name)
        {
            foreach (Scope sc in scopes)
            {
                foreach (Variable v in sc.variables)
                {
                    if (v.Name == Name)
                        return v.Type;
                }
            }
            return VType.NotFound;
        }
    }
}
